﻿#include "wxpolygonex.h"
#include <limits>

wxPolygonEx::wxPolygonEx(size_t n, const wxPoint points[])
{
    m_points.assign(points, points + n);
}

wxPolygonEx::wxPolygonEx(std::initializer_list<wxPoint> points)
    : m_points(points)
{
}

void wxPolygonEx::append(const wxPoint& point)
{
    m_points.push_back(point);
}

void wxPolygonEx::prepend(const wxPoint& point)
{
    m_points.insert(m_points.begin(), point);
}

void wxPolygonEx::insert(size_t index, const wxPoint& point)
{
    if (index > m_points.size()) {
        index = m_points.size();
    }
    m_points.insert(m_points.begin() + index, point);
}

void wxPolygonEx::remove(size_t index)
{
    if (index < m_points.size()) {
        m_points.erase(m_points.begin() + index);
    }
}

void wxPolygonEx::clear()
{
    m_points.clear();
}

wxPoint& wxPolygonEx::operator[](size_t index)
{
    return m_points[index];
}

const wxPoint& wxPolygonEx::operator[](size_t index) const
{
    return m_points[index];
}

wxPoint wxPolygonEx::at(size_t index) const
{
    if (index >= m_points.size()) {
        return wxPoint();
    }
    return m_points[index];
}

wxPoint wxPolygonEx::first() const
{
    if (m_points.empty()) {
        return wxPoint();
    }
    return m_points.front();
}

wxPoint wxPolygonEx::last() const
{
    if (m_points.empty()) {
        return wxPoint();
    }
    return m_points.back();
}

size_t wxPolygonEx::size() const
{
    return m_points.size();
}

bool wxPolygonEx::empty() const
{
    return m_points.empty();
}

bool wxPolygonEx::isClosed() const
{
    if (m_points.size() < 2) {
        return false;
    }
    return m_points.front() == m_points.back();
}

void wxPolygonEx::translate(int dx, int dy)
{
    for (auto& point : m_points) {
        point.x += dx;
        point.y += dy;
    }
}

wxPolygonEx wxPolygonEx::translated(int dx, int dy) const
{
    wxPolygonEx result(*this);
    result.translate(dx, dy);
    return result;
}

wxRect wxPolygonEx::boundingRect() const
{
    if (m_points.empty()) {
        return wxRect();
    }

    int minX = std::numeric_limits<int>::max();
    int minY = std::numeric_limits<int>::max();
    int maxX = std::numeric_limits<int>::min();
    int maxY = std::numeric_limits<int>::min();

    for (const auto& point : m_points) {
        minX = std::min(minX, point.x);
        minY = std::min(minY, point.y);
        maxX = std::max(maxX, point.x);
        maxY = std::max(maxY, point.y);
    }

    return wxRect(minX, minY, maxX - minX, maxY - minY);
}

bool wxPolygonEx::containsPoint(const wxPoint& pt) const
{
    if (m_points.size() < 3) {
        return false;
    }

    // 使用射线法判断点是否在多边形内
    return rayCasting(pt);
}

std::vector<wxPoint>::iterator wxPolygonEx::begin()
{
    return m_points.begin();
}

std::vector<wxPoint>::iterator wxPolygonEx::end()
{
    return m_points.end();
}

std::vector<wxPoint>::const_iterator wxPolygonEx::begin() const
{
    return m_points.begin();
}

std::vector<wxPoint>::const_iterator wxPolygonEx::end() const
{
    return m_points.end();
}

bool wxPolygonEx::rayCasting(const wxPoint& pt) const
{
    bool inside = false;
    size_t n = m_points.size();

    for (size_t i = 0, j = n - 1; i < n; j = i++) {
        const wxPoint& p1 = m_points[i];
        const wxPoint& p2 = m_points[j];

        if (((p1.y > pt.y) != (p2.y > pt.y)) &&
            (pt.x < (p2.x - p1.x) * (pt.y - p1.y) / (p2.y - p1.y) + p1.x)) {
            inside = !inside;
        }
    }

    return inside;
}
